class_name UnitGrid
extends Node
## 版本：1.0.0
## 功能：2D 网格布局和单元管理
## 使用：挂载到 Node 节点上，配置导出变量。
## 说明：
## 1. 单元 Unit 存放在单元格 Cell 上，所有单元格构成整个网格 Grid
## 2. 所有坐标都是局部网格坐标系
## 3. 单元 Unit 可以为任何类型

#region Signals
## 单元格上存在单元变化（单元添加或者移除）
signal unit_changed
#endregion

#region Exported parameters
## 以矩形网格初始化网格，x 表示列数，y 表示行数
@export var rect_grid_size: Vector2i
#endregion

#region Internal parameters
## 由所有单元格构成的网格，第一个分量是 Vector2i 网格坐标，第二个分量是 Unit 单元
var cells: Dictionary
#endregion


func _ready() -> void:
	# 使用矩形网格初始化网格
	for x in rect_grid_size.x:
		for y in rect_grid_size.y:
			add_cell(Vector2i(x, y))


#region 网格布局
## 判断指定局部网格坐标的单元格是否有单元（需要提前判断 is_cell_in_grid 为 true）
func is_cell_empty(cell_position: Vector2i) -> bool:
	return cells[cell_position] == null


## 判断网格中是否存在空单元格
func has_empty_cell() -> bool:
	return cells.keys().any(is_cell_empty)


## 获得第一个空单元格的局部网格坐标，当没有时返回无效位置 (-1, -1)
func get_first_empty_cell_position() -> Vector2i:
	for cell_position: Vector2i in cells.keys():
		if is_cell_empty(cell_position):
			return cell_position
	return Vector2i(-1, -1)


## 添加一个空单元格到指定局部网格坐标上，添加失败则返回 false
func add_cell(cell_position: Vector2i) -> bool:
	if is_cell_in_grid(cell_position):
		return false
	cells[cell_position] = null
	return true


## 判断指定局部网格坐标的单元格是否在网格中
func is_cell_in_grid(cell_position: Vector2i) -> bool:
	return cells.has(cell_position)
#endregion


#region 单元管理
## 添加一个单元到指定局部网格坐标的空单元格上，添加失败则返回 false
func add_unit_to_empty_cell(unit: Node, cell_position: Vector2i) -> bool:
	if not is_cell_in_grid(cell_position) or not is_cell_empty(cell_position):
		return false
	
	if unit.get_parent():
		unit.reparent(self)
	else:
		add_child(unit)
	
	cells[cell_position] = unit
	unit_changed.emit()
	return true


## 获得指定局部网格坐标单元格的单元（需要提前判断 is_cell_in_grid 为 true）
func get_unit(cell_position: Vector2i) -> Node:
	return cells[cell_position]


## 移除指定局部网格坐标单元格上的单元（网格中不会删除该单元格），移除失败则返回 false
func remove_unit_from_cell_position(cell_position: Vector2i) -> bool:
	if not is_cell_in_grid(cell_position) or is_cell_empty(cell_position):
		return false
	
	remove_child(cells[cell_position])
	cells[cell_position] = null
	unit_changed.emit()
	return true


## 移除网格中的指定单元（网格中不会删除该单元格），移除失败则返回 false
func remove_unit(unit: Node) -> bool:
	var cell_position = cells.find_key(unit)
	
	if not is_cell_in_grid(cell_position):
		return false
	
	remove_child(cells[cell_position])
	cells[cell_position] = null
	unit_changed.emit()
	return true


## 判断指定单元是否在网格中
func is_unit_in_grid(unit: Node) -> bool:
	return cells.find_key(unit) != null


## 获得指定单元在网格中的局部网格坐标
func get_unit_cell_position(unit: Unit) -> Vector2i:
	var cell_position = cells.find_key(unit)
	return cell_position if cell_position != null else Vector2i(-1, -1)


## 获得网格中所有的单元
func get_all_units() -> Array[Node]:
	var units: Array[Node]
	
	for unit: Node in cells.values():
		if unit:
			units.append(unit)
	
	return units
#endregion
